/*
 * helper.c
 * This file holds my helper functions that  initialize the
 * state of the game, compare array items, count treasure, issue
 * random cards, etc.
 *  Created on: Feb 13, 2014
 *      Author: Charles_OSU
 */

#include "dominion.h"
#include "dominion_helpers.h"
#include <stdio.h>
#include "rngs.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>

int doStop = 0;

/*  Function to set state back to a clean state for new game.
 *  This version creates a random number of players from 2-4
 *  and starts you with one action and one buy.
 */
void setState(struct gameState *state){
  int i;

 // state->numPlayers = 4;
  state->numPlayers = floor(Random() * (MAX_PLAYERS -1)) + 2; // Will generate 2,3, or 4 players
  for (i = adventurer; i <= treasure_map; i++){
    state->supplyCount[i] = 10;
    state->embargoTokens[i] = 0;
  }
  state->playedCardCount = 0;
  state->outpostPlayed = 0;
  state->outpostTurn = 0;
  state->whoseTurn = 0;
  state->coins = 0;
  state->phase = 0;
  state->numActions = 1; // we always have one action to start
   state->numBuys = 1; // always start with one buy
  for (i = 0; i< state->numPlayers; i++){
    state->handCount[i] = 0;
    state->deckCount[i] = 0;
    state->discardCount[i] = 0;
  }

}


/*  Function to return a random card.
 *  Use only if you don't need to actual int
 *  mapping to name of card. Otherwise use
 *
 */
int *randomCard(struct gameState *state){
    int random;
    int card;
    card = floor((Random() * 23)) + 1;

    switch(card){
        case 1:
            random = adventurer;
            break;
        case 2:
            random = council_room;
            break;
        case 3:
            random = feast;
            break;
        case 4:
            random = gardens;
            break;
        case 5:
            random = mine;
            break;
        case 6:
            random = remodel;
            break;
        case 7:
            random = smithy;
            break;
        case 8:
            random = village;
            break;
        case 9:
            random = baron;
            break;
        case 10:
            random = great_hall;
            break;
        case 11:
            random = minion;
            break;
        case 12:
            random = steward;
            break;
        case 13:
            random = tribute;
            break;
        case 14:
            random = ambassador;
            break;
        case 15:
            random = cutpurse;
            break;
        case 16:
            random = embargo;
            break;
        case 17:
            random = outpost;
            break;
        case 18:
            random = salvager;
            break;
        case 19:
            random = sea_hag;
            break;
        case 20:
            random = treasure_map;
            break;
        case 21:
        	random = gold;
        	break;
        case 22:
        	random = silver;
        	break;
        case 23:
        	random = copper;
        	break;
        case 24:
            random = *randomCard(state);
            break;
    }

        return (int*)random;
}


/*  Count the treasure cards in hand. If treasure > 2
 *  then return 0 (good state) otherwise we did not have
 *  at least 2 treasure cards and so return 1 (error)
 *
 */
int countTreasure(struct gameState *state){
    int i;
    int treasure = 0;
    for(i = 0; i < state->deckCount[0]; i++){
        if (state->deck[0][i]== gold || state->deck[0][i] == silver || state->deck[0][i] == copper){
        	treasure++;
        }
        if (treasure > 2){
            return 0;
        }
    }
    return 1;
}

/* Function to set hand with 10 random cards and
 * one adventurer card in hand
 *
 */
void setHandWithadventurer(struct gameState *state)
{
	int h;
	for(h = 0 ; h < state->numPlayers; h++)
	{
    int i;
    state->handCount[h] = 0;
    // Set our hand count to 10 starting
    for (i = 0; i < 10; i++){
        state->hand[h][i] = (int)*randomCard;
      //  printf("The card selected was %s\n",(int)state->hand[h][i]);
        state->handCount[h]++;
    }
    // And lastly always put the adventurer card in the hand somewhere
    int pos = floor((Random() * 10)) + 1;
    state->hand[h][pos] = adventurer;

	}
}

/* Function to set the deck to 50 random cards
 * and set treasure in hand. Uses randomCard()
 * function to return random cards so once again
 * use this only if you do not want to have
 * int value associated with cards
 *  */
void setDeck(struct gameState *state){
	int h;
	for(h = 0 ; h < state->numPlayers; h++)
	{
	int i;
    state->deckCount[h] = 0;
    for (i = 0; i < 50; i++){
        state->deck[h][i] = (int)*randomCard;
        state->deckCount[h]++;
    }
    state->deck[h][25] = copper;
    state->deck[h][30] = silver;
    state->deck[h][35] = gold;

	}

}


/*  Compare function to compare arrays
 *  of len length.
 *  Return 0 if same
 *  Return 1 if error
 *  */
int compareArray(int * a1, int * a2, int len)
{
	int i;
	for(i = 0; i < len; i++)
		if(a1[i] != a2[i])
			return 0;

	return 1;
}


// This function looks like it has been passed round all over the class. Not sure where it originated
// from but I borrowed it from allent
void printGameSummary(struct gameState gsPre,FILE *out, int gameNumber, int numPlayers)
{
        int i, j;
        fprintf(out,"\n\n");
        fprintf(out,"Game %d over:\n",gameNumber);

    // print scores
    for(i=0;i<27;i++){
                fprintf(out,"Supply Count for [%d]: %d\n",i,gsPre.supplyCount[i]);
    }

  for(i=0;i<numPlayers;i++)
  {
        fprintf(out,"Stats for Player %d\n", i);
    fprintf(out,"Score: %d\n", scoreFor(i, &gsPre));
    fprintf(out,"Deck: ");
                for(j=0;j<gsPre.deckCount[i];j++){
                        fprintf(out,"%d, ",gsPre.deck[i][j]);
        }
        fprintf(out,"\n");
            fprintf(out,"Player %d's hand: ",i);
                for(j=0;j<gsPre.handCount[i];j++){
                        fprintf(out,"%d, ",gsPre.hand[i][j]);
                }
        fprintf(out,"\n");

        fprintf(out,"Player %d's discard: ",i);
                for(j=0;j<gsPre.discardCount[i];j++){
                        fprintf(out,"%d, ",gsPre.discard[i][j]);
                }
        fprintf(out,"\n");

  fprintf(out,"Player %d's card summary: ",i);
    for(j=0;j<gsPre.discardCount[i];j++){
      fprintf(out,"%d, ",gsPre.discard[i][j]);
    }
  fprintf(out,"\n\n");

        }
}


/* Function that verifies player has 5 cards in hand
 * if cards in hand != 5 then +1 returned as error
 * that we add to error count
 */
int testNumberCardsHand(struct gameState* state){
	 int numerrors = 0;
	 int cards = numHandCards(state);
    //testing initial card in hand
    if(cards !=5){
        printf("number of cards was expected to be 5 in hand but were instead %d\n", cards);

    }
    return numerrors += 1;

}



/* Function to return the number of cards in the deck for
 * player sent in. Returns the number of the count.
 *  */
int testfullDeckCount(int player, int card, struct gameState *state) {
  int count = 0;

 count = fullDeckCount( player,  card, state);

  return count;
}


int testFailed;

void resetFlag(){
    testFailed = 0;
}

int testState(){
    return testFailed;
}

void incState(){
    testFailed++;
}

// converts card numbers to their string equivalents
char *cardToString(int number){
    switch(number){
        case 0:
            return "curse";
            break;
        case 1:
            return "estate";
            break;
        case 2:
            return "duchy";
            break;
        case 3:
            return "province";
            break;
        case 4:
            return "copper";
            break;
        case 5:
            return "silver";
            break;
        case 6:
            return "gold";
            break;
        case 7:
            return "adventurer";
            break;
        case 8:
            return "council_room";
            break;
        case 9:
            return "feast";
            break;
        case 10:
            return "gardens";
            break;
        case 11:
            return "mine";
            break;
        case 12:
            return "remodel";
            break;
        case 13:
            return "smithy";
            break;
        case 14:
            return "village";
            break;
        case 15:
            return "baron";
            break;
        case 16:
            return "great_hall";
            break;
        case 17:
            return "minion";
            break;
        case 18:
            return "steward";
            break;
        case 19:
            return "tribute";
            break;
        case 20:
            return "ambassador";
            break;
        case 21:
            return "cutpurse";
            break;
        case 22:
            return "embargo";
            break;
        case 23:
            return "outpost";
            break;
        case 24:
            return "salvager";
            break;
        case 25:
            return "sea_hag";
            break;
        case 26:
            return "treasure_map";
            break;
        default:
            return "";
            break;
    }
    return "";
}

void resetDeck(struct gameState *state){
    int i;
    int j;

  state->deckCount[0] = 0;
  state->deckCount[1] = 0;

  for (i = 0; i < state->numPlayers; i++)
    {
      state->deckCount[i] = 0;
      for (j = 0; j < 3; j++)
	{
	  state->deck[i][j] = estate;
	  state->deckCount[i]++;
	}
      for (j = 3; j < 10; j++)
	{
	  state->deck[i][j] = copper;
	  state->deckCount[i]++;
	}

	for (j = 0; j < 500; j++){
        state->discard[i][j] = -1;
        state->hand[i][j] = -1;
        state->playedCards[j] = -1;
        if (j >= 10)
            state->deck[i][j] = -1;
	}
    }
}

void assertMessage(char *message, int firstVal, int secondVal){
    printf(message, firstVal, secondVal);
    if (doStop == 1){
        assert(1 == 2);
    }
    incState();
}

int randInt(int low, int high)
{
	int temp = low + rand() % (high -low +1);
	return temp;

}
